Skip to content

fix(Board): always drop the selection on an in-widget control press - #1364

Merged
tenphi merged 1 commit into
mainfrom
andrew/cub-3827-board-pressing-an-in-widget-interactive-control-doesnt
Aug 26, 2026
Merged

fix(Board): always drop the selection on an in-widget control press#1364
tenphi merged 1 commit into
mainfrom
andrew/cub-3827-board-pressing-an-in-widget-interactive-control-doesnt

Conversation

@tenphi

@tenphi tenphi commented Aug 25, 2026

Copy link
Copy Markdown
Member

Fixes CUB-3827.

selectionCancel promises that pressing an interactive descendant of a widget drops the board selection, but the reset rode on the widget host's bubble-phase onPointerDown — so it only happened for presses that actually reached the host. A control that calls stopPropagation() first never got there, which is why a widget's gear/leaf button dropped the selection while the chart's mapping button and an inline delete button silently left it standing.

What changed

  • WidgetHost — the reset moved out of handleSelectPointerDown into two capture-phase handlers that only read the target (nothing is stopped or prevented, so every control keeps its press, focus and default behaviour):
    • a React onPointerDownCapture on the host. Capture runs top-down, so it lands before any descendant can call stopPropagation(), and because React propagates along the React tree it also covers a control the widget rendered into a portal (a menu opened from a widget's toolbar).
    • a native capture listener on the host node. React's capture phase is dispatched from the React root, so a descendant that stops the native event — charting and mapping libraries attach their own listeners and do exactly that — keeps it from reaching React at all. A listener on the host node itself sits below any such descendant. The two overlap in the ordinary case at no cost: clearing an already-empty selection is a no-op in commit.
  • Board — the marquee no longer starts from a press on content a widget portaled outside the board. React events arrive from portals along the React tree, so a press in a popover over the board used to be able to open a lasso behind it.
  • Docs line for selectionCancel now states the guarantee holds however the control handles the press.

Tests

Three regression specs under selection > clearing > however the press reaches the widget, one per way a press can miss the host: React stopPropagation, native stopPropagation, portaled control. All three fail on main and pass here.

pnpm test (2110 passed) and pnpm test:browser (127 passed) are green.

🤖 Generated with Claude Code


Note

Low Risk
Localized pointer-event ordering in Board selection/marquee; behavior is additive (clear selection earlier) with tests and no API changes.

Overview
Fixes CUB-3827: pressing a selectionCancel control inside a widget now always clears the board selection, including when the control stops propagation (React Aria, chart toolbars) or renders in a portal.

WidgetHost moves selection clearing out of bubble-phase onPointerDown into capture handlers that only inspect the target—no stopPropagation or preventDefault, so buttons and inputs keep normal press/focus behavior. A React onPointerDownCapture runs before descendants can block the event and still sees portaled UI in the widget’s React tree; a native pointerdown capture listener on the host covers libraries that stop the native event before React runs.

Board ignores marquee starts when the pointer target is outside the board content DOM, so a press on a portaled overlay no longer draws a lasso behind it.

Docs and regression tests cover React stopPropagation, native stopPropagation, and portaled controls.

Reviewed by Cursor Bugbot for commit 38a4826. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cube-ui-kit Ready Ready Preview Aug 25, 2026 5:50pm

Request Review

@changeset-bot

changeset-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 38a4826

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cube-dev/ui-kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏋️ Size limit report

Name Size Passed?
All 500.28 KB (+0.02% 🔺) Yes 🎉
Tree shaking (just a Button) 118.96 KB (0% 🟰) Yes 🎉

Compared against main at cc13939run 32876741389, 2026-08-25T17:14:44Z.

To see which modules changed, download the size-limit-statoscope-report artifact from this run and open report.html.

@github-actions

Copy link
Copy Markdown
Contributor

📦 NPM canary release

Deployed canary version 0.0.0-canary-c3b7b41.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Storybook is successfully deployed!

@tenphi
tenphi merged commit 9cf2d8d into main Aug 26, 2026
16 checks passed
@tenphi
tenphi deleted the andrew/cub-3827-board-pressing-an-in-widget-interactive-control-doesnt branch August 26, 2026 09:36
@tenphi tenphi mentioned this pull request Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant